/*
 * CombatModel.java
 *
 * @author Michael Hansen
 * @author Lukas Thuernagel
 * @author Soeren Warszus
 */

package risk.game;

import java.awt.event.ActionEvent;
import risk.dice.*;
import java.util.*;

/**
 *
 * 
 */
public class CombatModel {
    /**
     * Das zum Model dazugehoerige View zur Visualisierung der Ergebnisse
     */
    private CombatView view = null;
    
    /**
     * Angreiferland
     */
    private Territory attacker = null;
    
    /**
     * Verteidigerland
     */
    private Territory defender = null;
    
    /**
     * Truppenzahl des Angreifers
     */
    private int armySize = 0;
    
    /**
     * DiceModel zur Darstellung der Verteidigerwuerfel
     */
    private DiceModel defenderDiceModel;
    
    /**
     * DiceModel zur Darstellung der Angreiferwuerfel
     */
    private DiceModel attackerDiceModel;
    
    /**
     * FrontController, der benoetigt wird um manuell Aktionen zu feuern und
     * die Verarbeitung dem Controller zu ueberlassen.
     */
    private FrontController controller;

    
    /**
     * Erstellt eine neue Instanz von CombatModel.
     */
    public CombatModel() {
        // benoetigte Instanz von DiceModel erzeugen 
        this.attackerDiceModel = new DiceModel();
        this.defenderDiceModel = new DiceModel();
    }
    
    /**
     * Die Methode registriert einen View beim Model. 
     *
     * @param view  Der zu registrierende CombatView.
     */
    public void registerView (CombatView view, FrontController controller) 
    {
        if (view == null) {
            throw new IllegalArgumentException("Cannot add null object to CombatModel");
        }
        
        this.view       = view;
        this.controller = controller;
    }
    
    /**
     * Setzt das Angreifer- und Verteidigerland zur Vorbereitung auf einen Kampf.
     * 
     * @param attacker  Das Angreiferland
     * @param defender  Das Verteidigerland
     */
    public void setCombatTerritories(Territory attacker, Territory defender) {
        // Angreifer und Verteidiger festlegen
        this.attacker = attacker;
        this.defender = defender;
        
        // (moegliche) Truppenzahl des Angreifers festlegen
        this.setArmySize(this.attacker.getArmySize() - 1);

        this.view.updateCombatant();
    } 
    
    /**
     * Setzt die Anzahl der Angreifertruppe. Dies ist der entscheidende Wert
     * fuer die Anzahl der Angreiferwuerfel, der zwischen 1 und 3 liegen muss.
     *
     * @param armySize  Anzahl der Angreifertruppen.
     */
    public void setArmySize(int armySize) {
        if (armySize >= 3) {
            this.armySize = 3;
        } else {
            this.armySize = armySize;
        }
    }
    
    
    
    /**
     * Fuehrt einen Kampf zwischen Angreifer- und Verteidigerland aus.
     *
     * Dabei wird auf das zuvor gesetzte Angreiferland (inkl. Truppenanzahl 
     * zwischen 1-3) und Verteidigerland zurueckgegriffen. Die Methode 
     * verwendet zur Visualisierung die DiceModel fuer Angreifer und Verteidiger.
     * Nach dem Kampf werden entsprechen Truppen aus den Laendern abgezogen und
     * bei einer Eroberung alle noetigen Schritte unternommen, damit der 
     * Angreifer fortwaehrend als Besitzer des Landes gilt.
     */
    public void fight() {
        // Integer-Array fuer Wuerfelwurf des Angreifers und Verteidigers
        int[] diceAttacker = new int[3];
        int[] diceDefender = new int[2];
       
        this.view.updateDefenderDice(this.defender.getArmySize());
        this.view.updateAttackerDice(this.armySize);
        
        
        // Anzahl verschiebbarer Truppen bei einem Sieg des Angreifers
        int movableArmySize = this.view.getArmySize();
        
        // Wuerfelwuerfe fuer den Angreifer simulieren
        diceAttacker = this.attackerDiceModel.dice();

        // Wuerfelwuerfe fuer den Verteidiger simulieren
        diceDefender = this.defenderDiceModel.dice();
        
        
        System.out.println(Arrays.toString(diceAttacker));
        System.out.println(Arrays.toString(diceDefender));
        
        boolean lostDefender = false;
        if (diceAttacker[0] > diceDefender[0]) {
            // hoechster Wuerfelwurf des Angreifers hat gewonnen
            this.defender.setArmySize(this.defender.getArmySize() - 1);
            lostDefender = true;
        } else {
            // hoechster Wuerfelwurf des Angreifers hat verloren
            this.attacker.setArmySize(this.attacker.getArmySize() - 1);
            movableArmySize--;
        }
        
        // Gab es 2 Verteidiger? Gab es zudem 2 Angreifer?
        if (movableArmySize > 0 && ((this.defender.getArmySize() >= 2 && !lostDefender) || 
                (this.defender.getArmySize() >= 1 && lostDefender))) {
            if (diceAttacker[1] > diceDefender[1]) { 
                // 2. hoechster Wuerfelwurf des Angreifers hat gewonnen
                this.defender.setArmySize(this.defender.getArmySize() - 1);
            } else {
                // 2. hoechster Wuerfelwurf des Verteidigers hat gewonnen
                this.attacker.setArmySize(this.attacker.getArmySize() - 1);
                movableArmySize--;
            }
        }
        
        /* Besitzt der Verteidiger keine Truppen mehr, dann hat er das Land
           verloren */
        if (this.defender.getArmySize() == 0) {
            // Laender bei den Besitzern umtragen
            this.attacker.getOwner().setTerritory(this.defender);
            this.defender.getOwner().deleteTerritory(this.defender);
            // Besitzer beim eroberten Land umschreiben
            this.defender.setOwner(this.attacker.getOwner());
            // Truppenzahlen fuer beide Laender neu setzen
            this.defender.setArmySize(movableArmySize);
            this.attacker.setArmySize(this.attacker.getArmySize() - movableArmySize);
            
            // Kontinenteroberung ueberpruefen
            this.controller.actionPerformed(new ActionEvent(this, 0, "checkContinentBonus"));
        
            // Ueberpruefung, ob das Spiel beendet ist
            this.controller.actionPerformed(new ActionEvent(this, 0, "checkEndOfGame")); 
            
            // Wuerfeln deaktivieren (erst neue Landauswahl noetig)
            this.view.disableDicing();
        } else {
            // Wuerfeln deaktivieren, wenn Angreifer nur noch eine Einheit besitzt
            if (this.attacker.getArmySize() == 1) {
                this.view.disableDicing();
            }
            
            // ArmySize aktualisieren und Slider anpassen
            this.setArmySize(this.attacker.getArmySize() - 1);
            this.view.updateArmySize();
        }
    }

    
    /**
     * Setzt den zum Model gehoerigen View auf die Ausgangsdarstellung zurueck.
     */
    public void resetView() {
        if (this.view != null) {
            this.view.reset(); 
        }
    }

    /**
     * Gibt das Angreiferland zurueck.
     *
     * @return  Das Angreiferland
     */
    public Territory getAttacker() {
        return this.attacker;
    }
    
    /**
     * Gibt das Verteidigerland zurueck.
     *
     * @return  Das Verteidigerland
     */
    public Territory getDefender() {
        return this.defender;
    }
 
    /**
     * Gibt die Anzahl der Angriffstruppen zurueck.
     *
     * @return  Anzahl der Angreifertruppen
     */
    public int getArmySize() {
        return this.armySize;
    }
    
    /**
     * Gibt das DiceModel fuer die Verteidigerwuerfel zurueck.
     *
     * @return  DiceModel fuer die Verteidigerwuerfel
     */
    public DiceModel getDefenderDiceModel() {
        return this.defenderDiceModel;
    }
    
    /**
     * Gibt das DiceModel fuer die Angreiferwuerfel zurueck.
     * 
     * @return  DiceModel fuer die Angreiferwuerfel
     */
    public DiceModel getAttackerDiceModel() {
        return this.attackerDiceModel;
    }
}
